"""
提示词提炼服务
使用通义千问API将用户的中文描述转换为适合AI绘画的英文关键词
支持缓存和重试机制，提高性能和稳定性
"""

import logging
import json
import re
from typing import Optional, Dict, Any
from ..core.http_client import get_http_client
from ..core.cache import cache_response
from ..core.config import settings
from .retry_service import async_retry

logger = logging.getLogger(__name__)


class PromptRefinerService:
    """
    提示词提炼服务
    负责将中文自然语言描述转换为英文AI绘画关键词
    """

    def __init__(self):
        self.api_key = settings.dashscope_api_key
        self.api_base = settings.get_api_base_url("deepseek")  # 使用DashScope兼容模式
        self.model = "qwen-plus"  # 使用通义千问模型

        # 系统提示词模板
        self.system_prompt = """你是虚拟女友图片生成助手，将用户的自然语言转化为精准的英文提示词。

核心任务：提取用户请求的关键要素，生成25个词汇以内的英文提示词。

内容审核要求：
- 如遇裸体/色情要求，替换为合适服装（如：swimsuit, lingerie, pajamas, casual dress）
- 避免明确的性暗示词汇，转换为温馨浪漫的表达
- 保持画面美观且符合平台规范

优先级排序：
1. 核心动作/状态（用户的主要请求，去除不当内容）
2. 服装/装扮（必须详细，确保得体）
3. 场景/背景（必须明确）
4. 表情/情绪（温馨浪漫）
5. 构图/视角
6. 氛围/光影

输出要求：
- 严格控制在25个逗号分隔的英文词汇以内
- 优先保留用户请求的核心要素（去除不当部分）
- 符合日本二次元审美
- 每个维度最多3-4个词汇
- 确保内容健康向上

示例：
输入："我想看你在咖啡厅喝咖啡Z"
输出：drinking coffee,sitting,cafe interior,cozy atmosphere,warm lighting,gentle smile,casual dress,afternoon sunlight

替换示例：
用户要求"裸体" → 替换为"swimsuit"或"lingerie"
用户要求不当场景 → 替换为温馨场景如"bedroom,cozy"

只处理以"Z"结尾的"我想看XXX"格式请求，直接输出提示词，无需解释。"""

    @cache_response("prompt_refiner", ttl=3600)  # 缓存1小时
    @async_retry(retries=3, delay=1.0, backoff=2.0)
    async def refine_prompt(self, user_prompt: str) -> str:
        """
        提炼用户输入的中文提示词为英文关键词

        Args:
            user_prompt: 用户输入的中文描述

        Returns:
            str: 提炼后的英文关键词字符串

        Raises:
            ValueError: API调用失败或返回格式错误
        """
        if not user_prompt or not user_prompt.strip():
            logger.warning("用户提示词为空")
            return "1girl,solo"  # 默认关键词

        # 清理输入文本
        cleaned_prompt = self._clean_input(user_prompt)
        # 过滤不当内容
        filtered_prompt = self._filter_inappropriate_content(cleaned_prompt)
        logger.info(f"向大模型传递的提示词: {filtered_prompt}")

        try:
            # 构建请求消息
            messages = [
                {"role": "system", "content": self.system_prompt},
                {
                    "role": "user",
                    "content": f"请将以下中文描述转换为英文AI绘画关键词：{filtered_prompt}",
                },
            ]

            # 记录完整提示词
            logger.info(f"向大模型传递的系统指令: {self.system_prompt}")
            logger.info(
                f"向大模型传递的用户指令: 请将以下中文描述转换为英文AI绘画关键词：{filtered_prompt}"
            )

            # 调用通义千问API
            response_data = await self._call_qwen_api(messages)

            # 提取和清理返回的关键词
            refined_prompt = self._extract_keywords(response_data)

            logger.info(f"大模型返回的提炼结果: {refined_prompt}")
            return refined_prompt

        except Exception as e:
            logger.error(f"提示词提炼失败: {e}")
            # 返回基于规则的备用提炼结果
            return self._fallback_refine(filtered_prompt)

    async def _call_qwen_api(self, messages: list) -> Dict[str, Any]:
        """
        调用通义千问API

        Args:
            messages: 对话消息列表

        Returns:
            Dict: API响应数据
        """
        client = get_http_client()

        request_data = {
            "model": self.model,
            "messages": messages,
            "temperature": 0.1,  # 低温度确保输出稳定
            "max_tokens": 200,  # 限制输出长度
            "stream": False,
        }

        response = await client.post(
            f"{self.api_base}/chat/completions",
            headers={
                "Authorization": f"Bearer {self.api_key}",
                "Content-Type": "application/json",
            },
            json=request_data,
        )

        if response.status_code != 200:
            error_msg = f"通义千问API调用失败: {response.status_code} - {response.text}"
            logger.error(error_msg)
            raise ValueError(error_msg)

        # 记录API返回内容
        result = response.json()
        if "choices" in result and result["choices"]:
            logger.info(f"大模型原始返回: {result['choices'][0]['message']['content']}")

        return result

    def _extract_keywords(self, response_data: Dict[str, Any]) -> str:
        """
        从API响应中提取关键词

        Args:
            response_data: API响应数据

        Returns:
            str: 提取的英文关键词
        """
        try:
            if "choices" in response_data and len(response_data["choices"]) > 0:
                content = response_data["choices"][0]["message"]["content"]

                # 清理返回的内容
                keywords = self._clean_keywords(content)

                if keywords:
                    return keywords

            logger.warning("无法从API响应中提取有效关键词")
            return "1girl,solo"

        except Exception as e:
            logger.error(f"提取关键词失败: {e}")
            return "1girl,solo"

    def _clean_keywords(self, content: str) -> str:
        """
        清理和格式化关键词

        Args:
            content: 原始API返回内容

        Returns:
            str: 清理后的关键词字符串
        """
        # 移除可能的解释文本，只保留关键词
        lines = content.strip().split("\n")

        # 查找包含关键词的行
        keywords_line = ""
        for line in lines:
            line = line.strip()
            # 跳过空行和解释性文本
            if not line or line.startswith("输出：") or line.startswith("关键词："):
                continue
            # 找到包含逗号分隔关键词的行
            if "," in line and not line.endswith("："):
                keywords_line = line
                break

        if not keywords_line:
            keywords_line = lines[0] if lines else ""

        # 移除可能的前缀
        keywords_line = re.sub(
            r"^(输出[:：]|关键词[:：]|结果[:：])", "", keywords_line
        ).strip()

        # 清理关键词
        keywords = []
        for keyword in keywords_line.split(","):
            keyword = keyword.strip()
            # 移除引号和多余的标点
            keyword = re.sub(r'^["\'\s]+|["\'\s]+$', "", keyword)
            if keyword and self._is_valid_keyword(keyword):
                keywords.append(keyword)

        # 确保有基本的关键词
        if not keywords:
            return "1girl,solo"

        # 限制关键词数量（避免过长）
        keywords = keywords[:25]

        return ",".join(keywords)

    def _is_valid_keyword(self, keyword: str) -> bool:
        """
        验证关键词是否有效

        Args:
            keyword: 待验证的关键词

        Returns:
            bool: 是否为有效关键词
        """
        # 过滤掉无效的关键词
        invalid_patterns = [
            r"^[0-9]+$",  # 纯数字
            r"^[^\w\s]+$",  # 纯符号
            r"^\s*$",  # 空白
            r".{50,}",  # 过长的词
        ]

        for pattern in invalid_patterns:
            if re.match(pattern, keyword):
                return False

        return True

    def _clean_input(self, text: str) -> str:
        """
        清理用户输入的文本

        Args:
            text: 原始输入文本

        Returns:
            str: 清理后的文本
        """
        # 移除多余的空白字符
        text = " ".join(text.split())

        # 移除可能影响处理的特殊字符
        text = re.sub(r'[^\w\s\u4e00-\u9fff，。！？；：""' "（）【】]", "", text)

        # 限制长度
        if len(text) > 200:
            text = text[:200]

        return text.strip()

    def _fallback_refine(self, user_prompt: str) -> str:
        """
        基于规则的备用提示词提炼方法
        当API调用失败时使用

        Args:
            user_prompt: 用户输入的中文描述

        Returns:
            str: 基于规则提炼的关键词
        """
        logger.info(f"使用备用提炼方法: {user_prompt}")

        # 过滤不当内容
        user_prompt = self._filter_inappropriate_content(user_prompt)

        # 简单的关键词映射
        keyword_mapping = {
            # 人物相关
            "女孩": "girl",
            "男孩": "boy",
            "女人": "woman",
            "男人": "man",
            "少女": "girl",
            "少年": "boy",
            "美女": "beautiful girl",
            # 颜色相关
            "红色": "red",
            "蓝色": "blue",
            "绿色": "green",
            "黄色": "yellow",
            "粉色": "pink",
            "紫色": "purple",
            "黑色": "black",
            "白色": "white",
            "粉红色": "pink",
            "深蓝": "dark blue",
            "浅蓝": "light blue",
            # 服装相关
            "裙子": "dress",
            "衣服": "clothes",
            "晚礼服": "evening gown",
            "比基尼": "bikini",
            "制服": "uniform",
            "和服": "kimono",
            # 场景相关
            "海边": "beach",
            "咖啡厅": "cafe",
            "面包店": "bakery",
            "学校": "school",
            "公园": "park",
            "房间": "room",
            # 动作相关
            "坐着": "sitting",
            "站着": "standing",
            "跑步": "running",
            "微笑": "smiling",
            "拿着": "holding",
            "喝": "drinking",
            # 物品相关
            "咖啡": "coffee",
            "面包": "bread",
            "红豆包": "anpan",
            "书": "book",
            "花": "flower",
            "包": "bag",
        }

        # 提取关键词
        keywords = ["1girl", "solo"]  # 默认关键词

        for chinese, english in keyword_mapping.items():
            if chinese in user_prompt:
                if english not in keywords:
                    keywords.append(english)

        # 限制关键词数量
        keywords = keywords[:12]

        return ",".join(keywords)

    def _filter_inappropriate_content(self, text: str) -> str:
        """
        过滤和替换不当内容

        Args:
            text: 输入文本

        Returns:
            str: 过滤后的文本
        """
        # 不当内容映射表
        inappropriate_mapping = {
            # 裸体相关
            "裸体": "泳装",
            "全裸": "内衣",
            "裸": "比基尼",
            "脱衣": "内衣",
            "光身": "内衣",
            # 其他不当内容
            "色情": "魅力",
            "性感": "魅力",
            "诱惑": "迷人",
            "挑逗": "调皮",
            "撩人": "可爱",
        }

        filtered_text = text
        for inappropriate, replacement in inappropriate_mapping.items():
            filtered_text = filtered_text.replace(inappropriate, replacement)

        return filtered_text

    async def batch_refine_prompts(self, prompts: list) -> Dict[str, str]:
        """
        批量提炼提示词

        Args:
            prompts: 需要提炼的提示词列表

        Returns:
            Dict[str, str]: 原提示词到精炼提示词的映射
        """
        results = {}

        for prompt in prompts:
            try:
                refined = await self.refine_prompt(prompt)
                results[prompt] = refined
            except Exception as e:
                logger.error(f"批量提炼失败 {prompt}: {e}")
                results[prompt] = self._fallback_refine(prompt)

        return results

    def validate_refined_prompt(self, refined_prompt: str) -> bool:
        """
        验证提炼后的提示词是否符合要求

        Args:
            refined_prompt: 提炼后的提示词

        Returns:
            bool: 是否符合要求
        """
        if not refined_prompt or not refined_prompt.strip():
            return False

        # 检查是否包含基本的关键词
        keywords = refined_prompt.split(",")
        if len(keywords) < 2:
            return False

        # 检查是否为英文关键词
        english_pattern = re.compile(r"^[a-zA-Z\s_-]+$")
        for keyword in keywords[:3]:  # 检查前3个关键词
            if not english_pattern.match(keyword.strip()):
                return False

        return True


# 创建全局服务实例
prompt_refiner_service = PromptRefinerService()
